/*!
 * \file UftStrategyMgr.cpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief UFT策略管理器实现文件
 * 
 * \details 实现UFT策略管理器的所有功能，包括策略工厂的动态加载、
 *          策略实例的创建和管理、策略查找等核心功能。
 */
#include "UftStrategyMgr.h"

#include <boost/filesystem.hpp>

#include "../Share/StrUtil.hpp"
#include "../Share/StdUtils.hpp"

#include "../WTSTools/WTSLogger.h"

/*!
 * \brief 构造函数实现
 * 
 * \details 初始化UFT策略管理器，创建空的工厂映射表和策略映射表
 */
UftStrategyMgr::UftStrategyMgr()
{
}

/*!
 * \brief 析构函数实现
 * 
 * \details 清理策略管理器资源。由于使用了智能指针和RAII模式，
 *          资源会被自动释放，包括：
 *          - 策略实例由UftStraWrapper自动析构
 *          - 策略工厂由StraFactInfo析构函数自动释放
 *          - DLL模块会被自动卸载
 */
UftStrategyMgr::~UftStrategyMgr()
{
}

/*!
 * \brief 加载策略工厂实现
 * \param path 策略工厂DLL文件目录路径
 * \return bool 加载成功返回true，失败返回false
 * 
 * \details 扫描指定目录下的所有动态库文件，尝试加载UFT策略工厂：
 *          1. 检查目录是否存在
 *          2. 遍历目录中的所有文件
 *          3. 过滤出.dll(Windows)或.so(Linux)文件
 *          4. 加载动态库并获取工厂创建函数
 *          5. 创建工厂实例并注册到映射表
 *          6. 记录加载成功的工厂数量
 * 
 * \note 工厂DLL必须导出createStrategyFact和deleteStrategyFact函数
 * \warning 加载失败的DLL会被自动卸载，不会影响其他工厂的加载
 */
bool UftStrategyMgr::loadFactories(const char* path)
{
	if (!StdFile::exists(path))
	{
		WTSLogger::error("Directory %s of UFT strategy factory not exists", path);
		return false;
	}

	uint32_t count = 0;
	boost::filesystem::path myPath(path);
	boost::filesystem::directory_iterator endIter;
	for (boost::filesystem::directory_iterator iter(myPath); iter != endIter; iter++)
	{
		if (boost::filesystem::is_directory(iter->path()))
			continue;

#ifdef _WIN32
		if (iter->path().extension() != ".dll")
			continue;
#else //_UNIX
		if (iter->path().extension() != ".so")
			continue;
#endif

		// 加载动态库
		DllHandle hInst = DLLHelper::load_library(iter->path().string().c_str());
		if (hInst == NULL)
			continue;

		// 获取工厂创建函数
		FuncCreateUftStraFact creator = (FuncCreateUftStraFact)DLLHelper::get_symbol(hInst, "createStrategyFact");
		if (creator == NULL)
		{
			DLLHelper::free_library(hInst);
			continue;
		}
		
		// 创建工厂实例
		IUftStrategyFact* pFact = creator();
		if (pFact != NULL)
		{
			StraFactInfo& fInfo = _factories[pFact->getName()];

			fInfo._module_inst = hInst;
			fInfo._module_path = iter->path().string();
			fInfo._creator = creator;
			fInfo._remover = (FuncDeleteUftStraFact)DLLHelper::get_symbol(hInst, "deleteStrategyFact");
			fInfo._fact = pFact;
			WTSLogger::info("UFT strategy factory[%s] loaded", pFact->getName());

			count++;
		}
		else
		{
			DLLHelper::free_library(hInst);
			continue;
		}
	}

	WTSLogger::info("%u UFT strategy factories in directory[%s] loaded", count, path);

	return true;
}

/*!
 * \brief 根据工厂名称和策略名称创建策略实例
 * \param factname 工厂名称
 * \param unitname 策略单元名称  
 * \param id 策略实例ID
 * \return UftStrategyPtr 策略智能指针，创建失败返回空指针
 * 
 * \details 创建策略实例的详细过程：
 *          1. 根据工厂名称在工厂映射表中查找工厂信息
 *          2. 如果找到工厂，调用工厂的createStrategy方法创建策略
 *          3. 将策略实例封装到UftStraWrapper中
 *          4. 将策略添加到策略映射表中
 *          5. 返回策略智能指针
 * 
 * \note 策略ID必须唯一，重复ID会覆盖已存在的策略
 * \warning 如果工厂不存在，返回空指针
 */
UftStrategyPtr UftStrategyMgr::createStrategy(const char* factname, const char* unitname, const char* id)
{
	auto it = _factories.find(factname);
	if (it == _factories.end())
		return UftStrategyPtr();

	StraFactInfo& fInfo = (StraFactInfo&)it->second;
	UftStrategyPtr ret(new UftStraWrapper(fInfo._fact->createStrategy(unitname, id), fInfo._fact));
	_strategies[id] = ret;
	return ret;
}

/*!
 * \brief 根据完整策略名称创建策略实例
 * \param name 完整策略名称，格式为"工厂名.策略名"
 * \param id 策略实例ID
 * \return UftStrategyPtr 策略智能指针，创建失败返回空指针
 * 
 * \details 解析完整策略名称并创建策略实例：
 *          1. 使用"."分割策略名称，获取工厂名和策略单元名
 *          2. 验证名称格式是否正确（至少包含两部分）
 *          3. 调用重载的createStrategy方法创建策略
 * 
 * \note 策略名称格式必须为"工厂名.策略名"，否则创建失败
 * \warning 如果名称格式不正确或工厂不存在，返回空指针
 */
UftStrategyPtr UftStrategyMgr::createStrategy(const char* name, const char* id)
{
	StringVector ay = StrUtil::split(name, ".");
	if (ay.size() < 2)
		return UftStrategyPtr();

	const char* factname = ay[0].c_str();
	const char* unitname = ay[1].c_str();

	auto it = _factories.find(factname);
	if (it == _factories.end())
		return UftStrategyPtr();

	StraFactInfo& fInfo = (StraFactInfo&)it->second;
	UftStrategyPtr ret(new UftStraWrapper(fInfo._fact->createStrategy(unitname, id), fInfo._fact));
	_strategies[id] = ret;
	return ret;
}

/*!
 * \brief 根据ID获取策略实例
 * \param id 策略实例ID
 * \return UftStrategyPtr 策略智能指针，未找到返回空指针
 * 
 * \details 在策略映射表中查找指定ID的策略实例：
 *          1. 在_strategies映射表中查找指定ID
 *          2. 如果找到，返回对应的策略智能指针
 *          3. 如果未找到，返回空指针
 * 
 * \note 该方法提供对已创建策略的快速访问
 * \warning 如果策略ID不存在，返回空指针
 */
UftStrategyPtr UftStrategyMgr::getStrategy(const char* id)
{
	auto it = _strategies.find(id);
	if (it == _strategies.end())
		return UftStrategyPtr();

	return it->second;
}